/*
 * 86Box    A hypervisor and IBM PC system emulator that specializes in
 *          running old operating systems and software designed for IBM
 *          PC systems and compatibles from 1981 through fairly recent
 *          system designs based on the PCI bus.
 *
 *          This file is part of the 86Box distribution.
 *
 *          Handle the dialog for changing the program's language and other global settings.
 *
 *
 *
 * Authors: Laci bá'
 *
 *          Copyright 2021 Laci bá'
 *          Copyright 2021-2023 Jasmine Iwanek.
 */
#define UNICODE
#define BITMAP WINDOWS_BITMAP
#include <windows.h>
#include <windowsx.h>
#undef BITMAP
#include <commctrl.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <wchar.h>
#include <86box/86box.h>
#include <86box/config.h>
#include <86box/plat.h>
#include <86box/sound.h>
#include <86box/win.h>
#include <86box/ui.h>
#include <86box/resource.h>

/* Language */
static LCID temp_language;

static char temp_icon_set[256] = { 0 };

int enum_helper;
int c;

HWND hwndPreferences;

BOOL CALLBACK
EnumResLangProc(UNUSED(HMODULE hModule), UNUSED(LPCTSTR lpszType), UNUSED(LPCTSTR lpszName), WORD wIDLanguage, LONG_PTR lParam)
{
    wchar_t temp[LOCALE_NAME_MAX_LENGTH + 1];
    LCIDToLocaleName(wIDLanguage, temp, LOCALE_NAME_MAX_LENGTH, 0);
    wchar_t dispname[MAX_PATH + 1];
    GetLocaleInfoEx(temp, LOCALE_SENGLISHDISPLAYNAME, dispname, MAX_PATH);
    SendMessage((HWND) lParam, CB_ADDSTRING, 0, (LPARAM) dispname);
    SendMessage((HWND) lParam, CB_SETITEMDATA, c, (LPARAM) wIDLanguage);

    if (wIDLanguage == lang_id)
        enum_helper = c;
    c++;

    return 1;
}

/* Load available languages */
static void
preferences_fill_languages(HWND hdlg)
{
    temp_language   = GetThreadUILanguage();
    HWND lang_combo = GetDlgItem(hdlg, IDC_COMBO_LANG);

    SendMessage(lang_combo, CB_RESETCONTENT, 0, 0);
    SendMessage(lang_combo, CB_ADDSTRING, 0, win_get_string(IDS_7168));
    SendMessage(lang_combo, CB_SETITEMDATA, 0, 0xFFFF);

    enum_helper = 0;
    c           = 1;
    // if no one is selected, then it was 0xFFFF or unsupported language, in either case go with index enum_helper=0
    // also start enum index from c=1
    EnumResourceLanguages(hinstance, RT_MENU, L"MainMenu", &EnumResLangProc, (LPARAM) lang_combo);

    SendMessage(lang_combo, CB_SETCURSEL, enum_helper, 0);
}

/* Load available iconsets */
static void
preferences_fill_iconsets(HWND hdlg)
{
    HWND icon_combo = GetDlgItem(hdlg, IDC_COMBO_ICON);

    /* Add the default one */
    wchar_t buffer[512] = L"(";
    wcscat(buffer, plat_get_string(IDS_DEFAULT));
    wcscat(buffer, L")");

    SendMessage(icon_combo, CB_RESETCONTENT, 0, 0);
    SendMessage(icon_combo, CB_ADDSTRING, 0, (LPARAM) buffer);
    SendMessage(icon_combo, CB_SETITEMDATA, 0, (LPARAM) strdup(""));

    int combo_index = -1;

    /* Find for extra ones */
    HANDLE          hFind;
    WIN32_FIND_DATA data;

    char icon_path_root[512];
    win_get_icons_path(icon_path_root);

    wchar_t search[512];
    mbstoc16s(search, icon_path_root, strlen(icon_path_root) + 1);
    wcscat(search, L"*.*");

    hFind = FindFirstFile((LPCWSTR) search, &data);

    if (hFind != INVALID_HANDLE_VALUE) {
        do {
            if (wcscmp(data.cFileName, L".") && wcscmp(data.cFileName, L"..") && (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
                wchar_t temp[512]     = { 0 };
                wchar_t dispname[512] = { 0 };
                mbstoc16s(temp, icon_path_root, strlen(icon_path_root) + 1);
                wcscat(temp, data.cFileName);
                wcscat(temp, L"\\iconinfo.txt");

                wcscpy(dispname, data.cFileName);
                FILE *fp = _wfopen(temp, L"r");
                if (fp) {
                    char line[512] = { 0 };
                    if (fgets(line, 511, fp)) {
                        mbstoc16s(dispname, line, strlen(line) + 1);
                    }

                    fclose(fp);
                }

                char filename[512];
                c16stombs(filename, data.cFileName, 511);

                int index = SendMessage(icon_combo, CB_ADDSTRING, 0, (LPARAM) dispname);
                SendMessage(icon_combo, CB_SETITEMDATA, index, (LPARAM) (strdup(filename)));

                if (!strcmp(filename, icon_set))
                    combo_index = index;
            }
        } while (FindNextFile(hFind, &data));
        FindClose(hFind);
    }

    if (combo_index == -1) {
        combo_index = 0;
        strcpy(temp_icon_set, "");
    }

    SendMessage(icon_combo, CB_SETCURSEL, combo_index, 0);
}

/* This returns 1 if any variable has changed, 0 if not. */
static int
preferences_settings_changed(void)
{
    int i = 0;

    /* Language */
    i = i || has_language_changed(temp_language);
    i = i || strcmp(temp_icon_set, icon_set);

    return i;
}

/* IndexOf by ItemData */
static int
preferences_indexof(HWND combo, LPARAM itemdata)
{
    for (int i = 0; i < SendMessage(combo, CB_GETCOUNT, 0, 0); i++)
        if (SendMessage(combo, CB_GETITEMDATA, i, 0) == itemdata)
            return i;

    return -1;
}

/* This saves the settings back to the global variables. */
static void
preferences_settings_save(void)
{
    /* Language */
    set_language(temp_language);

    /* Iconset */
    strcpy(icon_set, temp_icon_set);
    win_load_icon_set();

    /* Update title bar */
    update_mouse_msg();

    /* Update status bar */
    config_changed = 1;
    ui_sb_set_ready(-1);
    ui_sb_update_panes();
    ui_sb_update_text();

    /* Save the language changes */
    config_save();
}

#if defined(__amd64__) || defined(__aarch64__)
static LRESULT CALLBACK
#else
static BOOL CALLBACK
#endif
PreferencesDlgProcedure(HWND hdlg, UINT message, WPARAM wParam, UNUSED(LPARAM lParam))
{
    switch (message) {
        case WM_INITDIALOG:
            hwndPreferences = hdlg;
            /* Language */
            temp_language = lang_id;
            strcpy(temp_icon_set, icon_set);
            preferences_fill_languages(hdlg);
            preferences_fill_iconsets(hdlg);
            break;

        case WM_COMMAND:
            switch (LOWORD(wParam)) {
                case IDOK:
                    if (preferences_settings_changed())
                        preferences_settings_save();
                    EndDialog(hdlg, 0);
                    return TRUE;

                case IDCANCEL:
                    EndDialog(hdlg, 0);
                    return TRUE;

                case IDC_COMBO_LANG:
                    if (HIWORD(wParam) == CBN_SELCHANGE) {
                        HWND combo    = GetDlgItem(hdlg, IDC_COMBO_LANG);
                        int  index    = SendMessage(combo, CB_GETCURSEL, 0, 0);
                        temp_language = SendMessage(combo, CB_GETITEMDATA, index, 0);
                    }
                    break;

                case IDC_COMBO_ICON:
                    if (HIWORD(wParam) == CBN_SELCHANGE) {
                        HWND combo = GetDlgItem(hdlg, IDC_COMBO_ICON);
                        int  index = SendMessage(combo, CB_GETCURSEL, 0, 0);
                        strcpy(temp_icon_set, (char *) SendMessage(combo, CB_GETITEMDATA, index, 0));
                    }
                    break;

                case IDC_BUTTON_DEFAULT:
                    {
                        HWND combo = GetDlgItem(hdlg, IDC_COMBO_LANG);
                        int  index = preferences_indexof(combo, DEFAULT_LANGUAGE);
                        SendMessage(combo, CB_SETCURSEL, index, 0);
                        temp_language = DEFAULT_LANGUAGE;
                        break;
                    }

                case IDC_BUTTON_DEFICON:
                    {
                        SendMessage(GetDlgItem(hdlg, IDC_COMBO_ICON), CB_SETCURSEL, 0, 0);
                        strcpy(temp_icon_set, "");
                        break;
                    }
                default:
                    break;
            }
            break;

        case WM_DESTROY:
            {
                LRESULT temp;
                HWND    combo = GetDlgItem(hdlg, IDC_COMBO_ICON);
                for (int i = 0; i < SendMessage(combo, CB_GETCOUNT, 0, 0); i++) {
                    temp = SendMessage(combo, CB_GETITEMDATA, i, 0);
                    if (temp) {
                        free((void *) temp);
                        SendMessage(combo, CB_SETITEMDATA, i, 0);
                    }
                }
            }
            break;
    }

    return FALSE;
}

void
PreferencesDlgCreate(HWND hwnd)
{
    DialogBox(hinstance, (LPCTSTR) DLG_PREFERENCES, hwnd, PreferencesDlgProcedure);
}
